<?php
namespace com\rs\dns\service;

use com\rs\dns\constant\DomainConstant;
use com\rs\dns\constant\UserManageConst;
use com\rs\dns\controller\api\vo\DomainForm;
use com\rs\dns\controller\api\vo\DomainInfo;
use com\rs\dns\controller\api\vo\DomainQuery;
use com\rs\dns\controller\api\vo\DomainStateSet;
use com\rs\dns\exception\BaException;
use com\rs\dns\repository\SoaRepository;
use com\rs\dns\repository\UrlRepository;
use com\rs\dns\service\user\impl\UserServiceImpl;
use restphp\biz\PageParam;
use restphp\utils\RestClassUtils;
use restphp\utils\RestLog;
use restphp\utils\RestStringUtils;

class DomainService {
    /**
     * 获取域名管理列表.
     * @param DomainQuery $domainQuery
     * @param PageParam $pageParam
     * @param string $username
     * @return \restphp\biz\RestPageReturn
     */
    public static function getDomainList($domainQuery, $pageParam, $username = '') {
        $arrRule = array(
        );
        if (!RestStringUtils::isBlank($username)) {
            $arrRule['username'] = $username;
        }
        if (!RestStringUtils::isBlank($domainQuery->getDomain())) {
            $arrRule['k1'] = array(
                ' origin like ? ',
                '%' . $domainQuery->getDomain() . '%'
            );
        }
        if (!RestStringUtils::isBlank($domainQuery->getUsername())) {
            $arrRule['username'] = $domainQuery->getUsername();
        }
        if (!RestStringUtils::isBlank($domainQuery->getYn())) {
            $arrRule['yn'] = $domainQuery->getYn();
        }

        $arrParams = array(
            'output' => ' * ',
            'rule' => $arrRule,
            'page_param' => $pageParam,
            'order' => ' order by id desc '
        );
        $soaRepository = new SoaRepository();
        return $soaRepository->getPageReturn($arrParams, new DomainInfo());
    }

    /**
     * 获取信息.
     * @param string $domain
     * @return mixed|null
     * @throws \restphp\exception\RestException
     */
    public static function getInfoByDomain($domain) {
        $arrRule = array(
            'origin' => $domain
        );
        $soaRepository = new SoaRepository();
        return $soaRepository->fineOne($arrRule);
    }

    /**
     * 获取信息.
     * @param integer $id
     * @return mixed|null
     * @throws \restphp\exception\RestException
     */
    public static function getInfoById($id) {
        $arrRule = array(
            'id' => $id
        );
        $soaRepository = new SoaRepository();
        return $soaRepository->fineOne($arrRule);
    }

    /**
     * 修改信息.
     * @param int $id
     * @param DomainForm $domainForm
     * @param string $username
     * @throws \restphp\exception\RestException
     */
    public static function modify($id, $domainForm, $username = '') {
        //域名处理
        $domainForm->setOrigin($domainForm->getOrigin() . '.');

        $soaRepository = new SoaRepository();

        //校验是否存在相关的域名
        //如果已存在abc.com的域名,不允许加入www.abc.com一类的域名
        $arrDomain = explode(".", $domainForm->getOrigin());
        for ($i=0; $i < count($arrDomain)-2; $i++) {
            $loopDomain = "";
            for ($j=$i; $j < count($arrDomain); $j++) {
                $loopDomain .= ("" == $loopDomain ? "" : ".") . $arrDomain[$j];
            }

            $domainExistsRule = array(
                'origin' => $loopDomain,
                'id' => array(
                    'id<>?',
                    $id
                )
            );
            $domainExists = $soaRepository->fineOne($domainExistsRule);
            if (null != $domainExists) {
                throw new BaException($loopDomain == $domainForm->getOrigin() ? DomainConstant::DOMAIN_EXISTS : DomainConstant::DOMAIN_PARENT_EXISTS);
            }
        }

        $arrRule = array(
            'id' => $id
        );
        if (!RestStringUtils::isBlank($username)) {
            $arrRule['username'] = $username;
        }

        $domainInfo = $soaRepository->fineOne($arrRule);
        if (null == $domainInfo) {
            throw new BaException(DomainConstant::DOMAIN_RECORD_NOT_EXISTS);
        }

        $arrData = RestClassUtils::beanToArr($domainForm);
        $soaRepository->update($arrData, $arrRule);

        // 更新转发
        $arrUpdateUrl = array(
            'k' => array(
                'domain=replace(domain , ?, ?)',
                array($domainInfo['origin'], $domainForm->getOrigin())
            )
        );
        $arrRuleUrl = array(
            'zone' => $id
        );
        $urlRepository = new UrlRepository();
        $urlRepository->update($arrUpdateUrl, $arrRuleUrl);

        //更新soa版本
        DomainService::updateSerial($id);
    }

    /**
     * 添加序列号.
     * @param DomainForm $domainForm
     * @throws BaException
     */
    public static function add($domainForm) {
        //域名处理
        $domainForm->setOrigin($domainForm->getOrigin() . '.');

        $soaRepository = new SoaRepository();

        //校验是否存在相关的域名
        //如果已存在abc.com的域名,不允许加入www.abc.com一类的域名
        $arrDomain = explode(".", $domainForm->getOrigin());
        for ($i=0; $i < count($arrDomain)-2; $i++) {
            $loopDomain = "";
            for ($j=$i; $j < count($arrDomain); $j++) {
                $loopDomain .= ("" == $loopDomain ? "" : ".") . $arrDomain[$j];
            }

            $domainExistsRule = array(
                'origin' => $loopDomain
            );
            $domainExists = $soaRepository->fineOne($domainExistsRule);
            if (null != $domainExists) {
                throw new BaException($loopDomain == $domainForm->getOrigin() ? DomainConstant::DOMAIN_EXISTS : DomainConstant::DOMAIN_PARENT_EXISTS);
            }
        }

        //校验用户域名数是否超出
        $userService = new UserServiceImpl();
        $user = $userService->getInfoByUsername($domainForm->getUsername());
        if (null == $user) {
            throw new BaException(UserManageConst::USER_NOT_EXIST);
        }
        $soaNum = $user->getSoanum();
        $hadDomainCountRule = array(
            'username' => $domainForm->getUsername()
        );
        $hadTotal = $soaRepository->countByMixRule($hadDomainCountRule);
        if ($soaNum <= $hadTotal) {
            throw new BaException(DomainConstant::DOMAIN_OVER_MAX_ALLOWED);
        }

        //写数据
        $arrData = RestClassUtils::beanToArr($domainForm);
        $arrData['ns'] = $domainForm->getOrigin();
        $arrData['mbox'] = $domainForm->getOrigin();
        $arrData['Serial'] = 1;
        $arrData['refresh'] = 900;
        $arrData['retry'] = 600;
        $arrData['expire'] = 86400;
        $arrData['minimum'] = 3600;
        $arrData['ttl'] = 3600;
        $soaRepository->insert($arrData);
    }

    /**
     * 设置域名状态
     * @param DomainStateSet $domainStateSet
     * @param string $username
     * @throws BaException
     */
    public static function setState($domainStateSet, $username = '') {
        $strDelRule = '';
        $arrSqlParam = array();
        foreach ($domainStateSet->getDomainIdList() as $id) {
            $strDelRule .= ('' == $strDelRule ? '' : ',') . '?';
            $arrSqlParam[] = $id;
        }
        $arrRule = array(
            "k" => array(
                " id in ({$strDelRule}) ",
                $arrSqlParam
            )
        );
        if (!RestStringUtils::isBlank($username)) {
            $arrRule['username'] = $username;
        }
        $soaRepository = new SoaRepository();
        $domainNum = $soaRepository->countByMixRule($arrRule);
        if ($domainNum != count($arrSqlParam)) {
            throw new BaException(DomainConstant::DOMAIN_RECORD_NOT_EXISTS);
        }

        $arrUpdate = array(
            'yn' => $domainStateSet->getYn()
        );
        $soaRepository = new SoaRepository();
        $soaRepository->update($arrUpdate, $arrRule);

        //更新soa版本
        foreach ($domainStateSet->getDomainIdList() as $id) {
            DomainService::updateSerial($id);
        }

    }

    /**
     * 删除序列号.
     * @param int $id
     * @param string $username
     * @throws \restphp\exception\RestException
     */
    public static function delete($id, $username='') {
        $arrRule = array(
            'ID' => $id
        );
        if (!RestStringUtils::isBlank($username)) {
            $arrRule['username'] = $username;
        }
        $soaRepository = new SoaRepository();
        $domainInfo = $soaRepository->fineOne($arrRule);
        if (null == $domainInfo) {
            throw new BaException(DomainConstant::DOMAIN_RECORD_NOT_EXISTS);
        }

        $soaRepository->delete($arrRule);
        //删除解析记录
        RecordService::deleteByZones(array($id));
        UrlService::deleteByZones(array($id));

        //更新soa版本
        DomainService::updateSerial($id);
    }

    /**
     * 删除.
     * @param $arrId
     * @throws BaException
     */
    public static function batchDelete($arrId, $username = '') {
        $strDelRule = '';
        $arrSqlParam = array();
        foreach ($arrId as $id) {
            if (!is_numeric($id)) {
                continue;
            }
            $strDelRule .= ('' == $strDelRule ? '' : ',') . '?';
            $arrSqlParam[] = $id;
        }
        if (empty($arrSqlParam)) {
            throw new BaException(DomainConstant::DOMAIN_TO_DELETE_CAN_NOT_NULL);
        }
        $arrRule = array(
            "k" => array(
                " id in ({$strDelRule}) ",
                $arrSqlParam
            )
        );
        if (!RestStringUtils::isBlank($username)) {
            $arrRule['username'] = $username;
        }

        //用户操作校验
        $soaRepository = new SoaRepository();
        $domainTotal = $soaRepository->countByMixRule($arrRule);
        if (count($arrSqlParam) != $domainTotal) {
            throw new BaException(DomainConstant::DOMAIN_RECORD_NOT_EXISTS);
        }

        $soaRepository->delete($arrRule);
        //删除解析记录
        RecordService::deleteByZones($arrId);
        UrlService::deleteByZones(array($id));


        //更新soa版本
        foreach ($arrId as $id) {
            if (!is_numeric($id)) {
                continue;
            }
            DomainService::updateSerial($id);
        }
    }

    /**
     * 根据用户名删除域名.
     * @param $arrUsernames
     */
    public static function clearByUsernames($arrUsernames) {
        $strDelRule = '';
        $arrSqlParam = array();
        foreach ($arrUsernames as $username) {
            $strDelRule .= ('' == $strDelRule ? '' : ',') . '?';
            $arrSqlParam[] = $username;
        }
        $arrRule = array(
            "k" => array(
                " username in ({$strDelRule}) ",
                $arrSqlParam
            )
        );
        $arrParams = array(
            'output' => 'id',
            'rule' => $arrRule
        );
        $soaRepository = new SoaRepository();
        $soaList = $soaRepository->select($arrParams);
        if (null == $soaList || empty($soaList)) {
            return;
        }

        $arrId = array();
        foreach ($soaList as $soa) {
            $arrId[] = $soa['id'];
        }

        self::batchDelete($arrId);
    }

    /**
     * 总计信息统计.
     */
    public static function statisticsAll() {
        // 正常.
        $soaRepository = new SoaRepository();
        $normal = $soaRepository->countByMixRule(array(
            'yn' => 1
        ));
        // 暂停
        $stop = $soaRepository->countByMixRule(array(
            'yn' => 0
        ));
        return array('normal' => $normal, 'stop' => $stop);
    }

    /**
     * 用户域名信息统计.
     * @param $username
     * @return array
     */
    public static function statisticsUser($username) {
        $soaRepository = new SoaRepository();
        $normal = $soaRepository->countByMixRule(array(
            'yn' => 1,
            'username' => $username
        ));
        // 暂停
        $stop = $soaRepository->countByMixRule(array(
            'yn' => 0,
            'username' => $username
        ));
        return array('normal' => $normal, 'stop' => $stop);
    }

    /**
     * 用户是否拥有指定域名.
     * @param string $domain 域名.
     * @param string $username 用户名.
     * @return bool
     */
    public static function hadDomain($domain, $username) {
        if (mb_substr($domain, mb_strlen($domain) - 1, mb_strlen($domain), 'UTF-8') != '.') {
            $domain .= '.';
        }
        $arrRule = array(
            'origin' => $domain,
            'username' => $username
        );
        $soaRepository = new SoaRepository();
        return $soaRepository->countByMixRule($arrRule, false, true) > 0;
    }

    /**
     * 是否存在域名
     * @param $domain
     * @param $username
     * @return bool
     */
    public static function hadDomainAdmin($domain) {
        if (mb_substr($domain, mb_strlen($domain) - 1, mb_strlen($domain), 'UTF-8') != '.') {
            $domain .= '.';
        }
        $arrRule = array(
            'origin' => $domain
        );
        $soaRepository = new SoaRepository();
        return $soaRepository->countByMixRule($arrRule, false, true) > 0;
    }

    /**
     * 解析版本更新
     * @param integer $id 域名ID.
     */
    public static function updateSerial($id) {
        $soaRepository = new SoaRepository();
        $arrUpdateSoa = array(
            'serial' => array('serial=serial+1')
        );
        $arrRuleSoa = array(
            'id' => $id
        );
        $soaRepository->update($arrUpdateSoa, $arrRuleSoa);
    }
}